using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Nice157Advices.Advices
{
    /// <summary>
    /// 16、元素数量可变的情况下不应使用数组
    /// </summary>
    public static class _16
    {
        // NOTE: 如果集合的数目固定并且不涉及转型，使用数组效率高，否则使用List<T>.

        /**
            在C#中，数组一旦被创建，长度就不能改变。如果我们需要一个动态且可变长度的集合，就应该使用ArrayList(不建议了)或List<T>来创建。而数组本身，尤其是一维数组，在遇到要求高效率的算法时，则会专门被优化以提升其效率。一维数组也成为向量，其性能是最佳的，在IL中使用了专门的指令来处理它们。

        　　从内存使用的角度来讲，数组具有以下特点：
        　　1、数组在创建时被分配了一段固定长度的内存。
        　　2、如果数组元素是值类型，则每个元素的长度等于相应的值类型的长度
        　　3、如果数组的元素是引用类型，则每个元素的长度为该引用类型的IntPtr.Size。
        　　4、数组的存储结构一旦被分配，就不能再变化。

        　　而ArryaList是这样的：
        　　1、ArrayList是链表结构，可以动态增减内存空间。
        　　2、如果ArrayList存储的是值类型，则会为每个元素增加12字节的空间，其中4字节用于对象引用，8字节是元素装箱时引入的对象头。
        　　而List<T>是ArrayList的泛型实现，它省去了拆箱和装箱带来的开销。
         */
        public static void Go ()
        {
            ResizeArray ();
            ResizeList ();
        }

        private static void ResizeList ()
        {
            List<int> list = new List<int> () { 0, 1, 2, 3, 4, 5, 6 };
            Stopwatch watch = new Stopwatch ();
            watch.Start ();
            list.Add (0);
            list.Add (0);
            list.Add (0);
            watch.Stop ();
            System.Console.WriteLine ($"ResizeList: {watch.Elapsed}");
        }

        private static void ResizeArray ()
        {
            int[] arr = { 0, 1, 2, 3, 4, 5, 6 };
            Stopwatch watch = new Stopwatch ();
            watch.Start ();
            arr.ReSize (10);
            watch.Stop ();
            System.Console.WriteLine ($"ResizeArray: {watch.Elapsed}");
        }
    }

    public static class ClassForExtensions
    {
        public static Array ReSize (this Array array, int newSize)
        {
            Type t = array.GetType ().GetElementType ();
            Array newArray = Array.CreateInstance (t, newSize);
            Array.Copy (array, newArray, Math.Min (array.Length, newSize));
            return newArray;
        }
    }
}